#ifndef __ZONGYI_FRAC_SOLVER_HPP__
#define __ZONGYI_FRAC_SOLVER_HPP__

#include "solver_types.h"
#include "gpu_solver_types.cuh"

class FracSolver
{
public:
    size_t capacity = 0;
    double* h_A13 = nullptr, * h_A23 = nullptr, * h_A31 = nullptr, * h_A32 = nullptr, * h_A33 = nullptr;// 容量为capacity
    double* d_A13 = nullptr, * d_A23 = nullptr, * d_A31 = nullptr, * d_A32 = nullptr, * d_A33 = nullptr;// 容量为capacity
    double* h_solid = nullptr, * d_solid = nullptr;
    double* d_x1_2 = nullptr;// 容量为 2*capacity
    double* d_x3 = nullptr, * d_b3 = nullptr, * d_p1 = nullptr, * d_p2 = nullptr, * d_p3 = nullptr;// 容量为 capacity
    // double* h_As = nullptr, * d_As = nullptr;// 容量为 (2*capacity) x (2*capacity)
    double* d_As = nullptr;
    // double* reo_invA = nullptr;
    int last_nrows = 0;
    double* last_mem = nullptr;// 上一次分解的LU结果
    std::vector<int> prev_hfs;
    int* map_mem = nullptr, * map_o2n = nullptr, * map_n2o = nullptr;
    int* d_map_mem = nullptr, * d_map_o2n = nullptr, * d_map_n2o = nullptr;
    cublasHandle_t blas_handle = nullptr;
    cusolverDnHandle_t sol_handle = nullptr;
    size_t hbuf_len[5] = {0, 0, 0, 0, 0};
    double* hbuf[5] = {nullptr, nullptr, nullptr, nullptr, nullptr};
    double* invLU = nullptr, * invAs = nullptr;

    double t_trans = 0.0, t_setup = 0.0, t_trsv = 0.0, t_gemv = 0.0;
    int invoked_cnt = 0;
    int wait_cnt = 10;
    
    // int gemv_cnt = 0;
    // double* mat_arrs[5];
    // int mat_size[5] = {0, 0, 0, 0, 0};
    // int mat_capa[5];


    const int solver_type = -1;
    const int prec_type = -1;

    FracSolver(int _sol_type, int _pc_type, size_t _capa);
    ~FracSolver();
    
    void solve( const int fluid_nrows, const int fluid_lda,
                const double* solid_A,
                const double* A13, const double* A23, const double* A31, const double* A32, const double* A33,
                const double* b1, const double* b2, const double* x3,
                double* x1_2, double* b3
    );

    void gemv(  const int fluid_nrows, const int fluid_lda,
                const double* A, const double* x, double* y, int* x_start, int* x_end);
};

void deep_copy(const FracSolver * old_solver, FracSolver * new_solver);

#endif